package com.ming.job.xxljob.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.ming.common.Options;
import com.ming.common.SortBy;
import com.ming.common.beetl.util.Result;
import com.ming.common.beetl.util.StrUtil;
import com.ming.common.xxljob.annotation.PermissionLimit;
import com.ming.common.xxljob.biz.ExecutorBiz;
import com.ming.common.xxljob.biz.model.KillParam;
import com.ming.common.xxljob.biz.model.LogParam;
import com.ming.common.xxljob.biz.model.LogResult;
import com.ming.common.xxljob.biz.model.ReturnT;
import com.ming.job.core.complete.XxlJobCompleter;
import com.ming.job.core.scheduler.XxlJobScheduler;
import com.ming.job.core.util.I18nUtil;
import com.ming.job.xxljob.entity.XxlJobInfo;
import com.ming.job.xxljob.entity.XxlJobLog;
import com.ming.job.xxljob.vo.XxlJobLogVo;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.page.PageResult;
import org.beetl.sql.core.query.LambdaQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("/xxljob/log")
public class IvyXxlJobLogController {

    private static final Logger logger = LoggerFactory.getLogger(IvyXxlJobLogController.class);

    @Resource
    private SQLManager sqlManager;

    @PostMapping("/page")
    @PermissionLimit(limit = false)
    public Result<PageResult<XxlJobLog>> page(@RequestBody XxlJobLogVo vo){
        // parse param
        Integer logStatus = vo.getLogStatus();
        String triggerTimeStart = null;
        String triggerTimeEnd = null;
        String filterTime = vo.getFilterTime();
        if (filterTime != null && filterTime.trim().length() > 0) {
            if(filterTime.contains(" to ")){
                String[] temp = filterTime.split(" to ");
                if (temp.length == 2) {
                    triggerTimeStart = temp[0]+" 00:00:00";
                    triggerTimeEnd = temp[1]+" 23:59:59";
                }
            }else{
                triggerTimeStart = filterTime+" 00:00:00";
                triggerTimeEnd = filterTime+" 23:59:59";
            }
        }

        LambdaQuery<XxlJobLog> lambdaQuery = sqlManager.lambdaQuery(XxlJobLog.class);
        lambdaQuery.andEq(XxlJobLog::getJobId, LambdaQuery.filterEmpty(vo.getJobId()));
        lambdaQuery.andEq(XxlJobLog::getJobGroup, LambdaQuery.filterEmpty(vo.getJobGroup()));
        lambdaQuery.andGreatEq(XxlJobLog::getTriggerTime, LambdaQuery.filterEmpty(triggerTimeStart));
        lambdaQuery.andLessEq(XxlJobLog::getTriggerTime, LambdaQuery.filterEmpty(triggerTimeEnd));
        if(vo.getLogStatus() != null){
            if(logStatus == 1){
                lambdaQuery.andEq(XxlJobLog::getHandleCode, 200);
            }else if(logStatus == 2){
                LambdaQuery<XxlJobLog> condition = lambdaQuery.condition();
                condition.orNotIn(XxlJobLog::getTriggerCode, CollUtil.toList(0,200));
                condition.orNotIn(XxlJobLog::getHandleCode, CollUtil.toList(0,200));
                lambdaQuery.and(condition);
            }else if(logStatus == 3){
                lambdaQuery.andEq(XxlJobLog::getTriggerCode, 200);
                lambdaQuery.andEq(XxlJobLog::getHandleCode, 0);
            }
        }
        Options options = vo.getOptions();
        List<SortBy> sortBy = options.getSortBy();
        for (SortBy sort : sortBy) {
            if ("desc".equalsIgnoreCase(sort.getOrder())) {
                lambdaQuery.desc(StrUtil.camelToSnake(sort.getKey()));
            } else {
                lambdaQuery.asc(StrUtil.camelToSnake(sort.getKey()));
            }
        }
        PageResult<XxlJobLog> page = lambdaQuery.page(options.getPage(), options.getItemsPerPage());
        return Result.OK(page);
    }

    @PostMapping("/add")
    @PermissionLimit(limit = false)
    public Result<?> add(@RequestBody XxlJobLog item){
        LambdaQuery<XxlJobLog> query = sqlManager.lambdaQuery(XxlJobLog.class);
        int i = query.insert(item);
        return Result.OK(i);
    }

    @PostMapping("/update")
    @PermissionLimit(limit = false)
    public Result<Object> update(@RequestBody XxlJobLog item){
        int i = sqlManager.updateById(item);
        return Result.OK("更新成功", i);
    }

    @PostMapping("/delete")
    @PermissionLimit(limit = false)
    public Result<Integer> delete(@RequestBody XxlJobLog item){
        LambdaQuery<XxlJobLog> lambdaQuery = sqlManager.lambdaQuery(XxlJobLog.class);
        lambdaQuery.andEq(XxlJobLog::getId, item.getId());
        int i = lambdaQuery.delete();
        return Result.OK("删除成功",i);
    }

    @PostMapping("/clear")
    @PermissionLimit(limit = false)
    public Result<?> clear(@RequestBody XxlJobLogVo vo){
        Integer logStatus = vo.getLogStatus();
        String triggerTimeStart = null;
        String triggerTimeEnd = null;
        String filterTime = vo.getFilterTime();
        if (filterTime != null && filterTime.trim().length() > 0) {
            if(filterTime.contains(" to ")){
                String[] temp = filterTime.split(" to ");
                if (temp.length == 2) {
                    triggerTimeStart = temp[0]+" 00:00:00";
                    triggerTimeEnd = temp[1]+" 23:59:59";
                }
            }else{
                triggerTimeStart = filterTime+" 00:00:00";
                triggerTimeEnd = filterTime+" 23:59:59";
            }
        }

        LambdaQuery<XxlJobLog> lambdaQuery = sqlManager.lambdaQuery(XxlJobLog.class);
        lambdaQuery.andEq(XxlJobLog::getJobId, LambdaQuery.filterEmpty(vo.getJobId()));
        lambdaQuery.andEq(XxlJobLog::getJobGroup, LambdaQuery.filterEmpty(vo.getJobGroup()));
        lambdaQuery.andGreatEq(XxlJobLog::getTriggerTime, LambdaQuery.filterEmpty(triggerTimeStart));
        lambdaQuery.andLessEq(XxlJobLog::getTriggerTime, LambdaQuery.filterEmpty(triggerTimeEnd));
        if(vo.getLogStatus() != null){
            if(logStatus == 1){
                lambdaQuery.andEq(XxlJobLog::getHandleCode, 200);
            }else if(logStatus == 2){
                LambdaQuery<XxlJobLog> condition = lambdaQuery.condition();
                condition.orNotIn(XxlJobLog::getTriggerCode, CollUtil.toList(0,200));
                condition.orNotIn(XxlJobLog::getHandleCode, CollUtil.toList(0,200));
                lambdaQuery.and(condition);
            }else if(logStatus == 3){
                lambdaQuery.andEq(XxlJobLog::getTriggerCode, 200);
                lambdaQuery.andEq(XxlJobLog::getHandleCode, 0);
            }
        }
        int i = lambdaQuery.delete();
        return Result.OK("清理成功："+i+"条",i);
    }

    @PostMapping("/logDetailCat")
    @PermissionLimit(limit = false)
    public Result<?> logDetailCat(@RequestBody XxlJobLogVo vo){
        try {
            long logId = vo.getId();
            int fromLineNum = vo.getFromLineNum();
            // valid
            LambdaQuery<XxlJobLog> query = sqlManager.lambdaQuery(XxlJobLog.class);
            query.andEq(XxlJobLog::getId, logId);
            XxlJobLog jobLog = query.single();
            if (jobLog == null) {
                return Result.error(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_logid_unvalid"));
            }

            // log cat
            ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(jobLog.getExecutorAddress());
            String triggerTime = jobLog.getTriggerTime();

            ReturnT<LogResult> logResult = executorBiz.log(new LogParam(DateUtil.parse(triggerTime).getTime(), logId, fromLineNum));

            // is end
            if (logResult.getContent()!=null && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) {
                if (jobLog.getHandleCode() > 0) {
                    logResult.getContent().setEnd(true);
                }
            }
            return Result.OK(logResult.getCode(),logResult.getMsg(),logResult.getContent());
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return Result.error(ReturnT.FAIL_CODE, e.getMessage());
        }
    }

    @PostMapping("/kill")
    @PermissionLimit(limit = false)
    public Result<?> kill(@RequestBody XxlJobLogVo vo){
        long id = vo.getId();
        // base check
        LambdaQuery<XxlJobLog> query = sqlManager.lambdaQuery(XxlJobLog.class);
        query.andEq(XxlJobLog::getId, id);
        XxlJobLog log = query.single();

        LambdaQuery<XxlJobInfo> lambdaQuery = sqlManager.lambdaQuery(XxlJobInfo.class);
        lambdaQuery.andEq(XxlJobInfo::getId, log.getJobId());
        XxlJobInfo jobInfo = lambdaQuery.single();

        if (jobInfo == null) {
            return Result.error(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
        }
        if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) {
            return Result.error(500, I18nUtil.getString("joblog_kill_log_limit"));
        }

        // request of kill
        ReturnT<String> runResult = null;
        try {
            ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(log.getExecutorAddress());
            runResult = executorBiz.kill(new KillParam(jobInfo.getId()));
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            runResult = new ReturnT<String>(500, e.getMessage());
        }

        if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
            log.setHandleCode(ReturnT.FAIL_CODE);
            log.setHandleMsg( I18nUtil.getString("joblog_kill_log_byman")+":" + (runResult.getMsg()!=null?runResult.getMsg():""));
            log.setHandleTime(DateUtil.now());

            com.ming.job.core.model.XxlJobLog targetObj = new com.ming.job.core.model.XxlJobLog();
            BeanUtil.copyProperties(log, targetObj);
            XxlJobCompleter.updateHandleInfoAndFinish(targetObj);
            return Result.OK(runResult.getMsg(),null);
        } else {
            return Result.error(500, runResult.getMsg());
        }
    }
}
